﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
//using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Media.Imaging;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Phone.Applications.Common;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Factories;
using FarseerPhysics.SamplesFramework;
using FarseerPhysics.Dynamics.Joints;
using Microsoft.Phone.Controls;
//using Microsoft.Xna.Framework;
//using Microsoft.Xna.Framework;

namespace BootyShaker
{

    public partial class ShakeObject : UserControl
    {

        public System.Windows.Point destination = new Point(0, 0);
        //public System.Windows.Point location = new Point(0, 0);

        private Canvas parent;
        private Size size;
        private int acceleration = 1000;

        public List<Texture2D> texturesList;
        public ShakeObject(System.Windows.Point loc, Size sz, Canvas ctl, int speed)
        {
            InitializeComponent();
            parent = ctl;
            // this.location = loc;
            this.destination = loc;
            this.forcePoint = new Simple3DVector();
            this.size = sz;
            this.Width = sz.Width;
            this.Height = sz.Height;
            Canvas.SetLeft(this, 0);
            Canvas.SetTop(this, 0);
            Canvas.SetZIndex(this, Int16.MaxValue - 1);
            //sourceImg = img;
            //LoadImage(img, shakePanel);
            drag = false;
            //this.parent = par;
            this.acceleration = speed;
            //mainellipse.MouseMove += new MouseEventHandler(objMouseMove);
            //mainellipse.MouseLeftButtonDown += new MouseButtonEventHandler(objMouseDown);
            //mainellipse.MouseLeftButtonUp += new MouseButtonEventHandler(objMouseUp);
            //this.ManipulationDelta += new EventHandler<ManipulationDeltaEventArgs>(manipulationDelta);
            // this.RenderTransform = new CompositeTransform();
            objTransform = new CompositeTransform();
            this.RenderTransform = objTransform;

        }

        CompositeTransform objTransform;
        double initialAngle;
        double initialScale;
        private void OnTap(object sender, GestureEventArgs e)
        {
            objTransform.TranslateX = objTransform.TranslateY = 0;
            e.Handled = true;
        }

        private void OnDoubleTap(object sender, GestureEventArgs e)
        {
            objTransform.ScaleX = objTransform.ScaleY = 1;
            e.Handled = true;
        }

        private void OnHold(object sender, GestureEventArgs e)
        {
            objTransform.TranslateX = objTransform.TranslateY = 0;
            objTransform.ScaleX = objTransform.ScaleY = 1;
            objTransform.Rotation = 0;
            e.Handled = true;
        }

        private void OnDragStarted(object sender, DragStartedGestureEventArgs e)
        {
            // border.Background = greenBrush;
            e.Handled = true;
        }

        private void OnDragDelta(object sender, DragDeltaGestureEventArgs e)
        {
            objTransform.TranslateX += e.HorizontalChange;
            objTransform.TranslateY += e.VerticalChange;
            e.Handled = true;
        }

        private void OnDragCompleted(object sender, DragCompletedGestureEventArgs e)
        {
            // border.Background = normalBrush;
        }

        private void OnPinchStarted(object sender, PinchStartedGestureEventArgs e)
        {
            //border.Background = redBrush;

            //initialAngle = objTransform.Rotation;
            initialScale = objTransform.ScaleX;
            e.Handled = true;
        }

        private void OnPinchDelta(object sender, PinchGestureEventArgs e)
        {
            //objTransform.Rotation = initialAngle + e.TotalAngleDelta;
            objTransform.ScaleX = objTransform.ScaleY = initialScale * e.DistanceRatio;
            e.Handled = true;
        }

        private void OnPinchCompleted(object sender, PinchGestureEventArgs e)
        {
            //border.Background = normalBrush;
            e.Handled = true;
        }

        private void OnFlick(object sender, FlickGestureEventArgs e)
        {
            // flickData.Text = string.Format("{0} Flick: Angle {1} Velocity {2},{3}",
            //  e.Direction, Math.Round(e.Angle), e.HorizontalVelocity, e.VerticalVelocity);
        }

        private void manipulationDelta(object sender, System.Windows.Input.ManipulationDeltaEventArgs e)
        {
            //ReportEvent("Manipulation Delta Event: ");
            ShakeObject obj = sender as ShakeObject;
            CompositeTransform compositeTransform =
              obj.RenderTransform as CompositeTransform;

            if ((e.DeltaManipulation.Scale.X > 0) || (e.DeltaManipulation.Scale.Y > 0))
            {
                double ScaleValue = Math.Max(e.DeltaManipulation.Scale.X,
                  e.DeltaManipulation.Scale.Y);
                System.Diagnostics.Debug.WriteLine("Scale Value: " +
                  ScaleValue.ToString());

                //Limit how large
                if ((compositeTransform.ScaleX <= 4d) || (ScaleValue < 1d))
                {
                    compositeTransform.ScaleX *= ScaleValue;
                    compositeTransform.ScaleY *= ScaleValue;
                    compositeTransform.CenterX = e.ManipulationOrigin.X;
                    compositeTransform.CenterY = e.ManipulationOrigin.Y;
                }




            }
            System.Diagnostics.Debug.WriteLine("compositeTransform.ScaleX: " +
              compositeTransform.ScaleX);
            System.Diagnostics.Debug.WriteLine("compositeTransform.ScaleY: " +
              compositeTransform.ScaleY);

            compositeTransform.TranslateX += e.DeltaManipulation.Translation.X;
            compositeTransform.TranslateY += e.DeltaManipulation.Translation.Y;
            e.Handled = true;
        }
        private WriteableBitmap cropImage(WriteableBitmap img)
        {
            Size siz = getsize();
            WriteableBitmap CroppedImage = new WriteableBitmap((int)siz.Width, (int)siz.Height);

            // Copy the pixels from the targeted region of the source image into the target image, 
            // using the calculated offset
            for (int k = 0; k < CroppedImage.Pixels.Length; k++)
            {
                int x = (int)((k % CroppedImage.PixelWidth) + this.destination.X - siz.Width/2 - App.ShakeImagePos.X);
                int y = (int)((k / CroppedImage.PixelWidth) + this.destination.Y - siz.Height/2 - App.ShakeImagePos.Y);
                if (x > 0 && y > 0)
                {
                    try
                    {
                        CroppedImage.Pixels[k] = img.Pixels[y * img.PixelWidth + x];
                    }
                    catch (Exception ex) 
                    {
                    }
                }
            }
            return CroppedImage;
        }
        private Size getsize()
        {
            return new Size(this.ActualWidth * ((CompositeTransform)this.RenderTransform).ScaleX, this.ActualHeight * ((CompositeTransform)this.RenderTransform).ScaleY);
        }
        int StepFraction = 30;
        int minStep = 4;
        public Texture2D LoadImage(GraphicsDevice gd, World World)
        {
            //TODO - gal viska su Float??
            int start = StepFraction;
            int end = minStep;
            //MainImage.Source = App.CapturedImage;
            // this.location = App.gt.Transform(new Point (Canvas.GetLeft(this),Canvas.GetTop(this)));

            //this.destination = App.gt.Transform(new Point(Canvas.GetLeft(this), Canvas.GetTop(this)));
            Size siz = getsize();
            this.destination = App.gt.Transform(this.RenderTransform.Transform(new Point(this.ActualWidth / 2, this.ActualHeight / 2)));
            WriteableBitmap shakeimg = cropImage(App.ShakeImageTransformed);
            texturesList = new List<Texture2D>();
            // List<Ellipse> ellipses = new List<Ellipse>();

            for (int i = start; i > end; i--)
            {

                Size sz = new Size(siz.Width * i / StepFraction, siz.Height * i / StepFraction);
                //System.Windows.Point lc = new System.Windows.Point((int)this.destination.X - sz.Width / 2, (int)this.destination.Y - sz.Height / 2);

                // Point lc = this.destination;

                Ellipse ellipse = new Ellipse();



                ImageBrush ib = new ImageBrush();

                ib.ImageSource = shakeimg;
                ib.Stretch = Stretch.None;
                ellipse.Fill = ib;
                RadialGradientBrush rgb = new RadialGradientBrush(Colors.Black, Colors.Transparent);
                rgb.GradientStops[0].Offset = 0.8;
                ellipse.OpacityMask = rgb;
                ellipse.StrokeThickness = 1;
                //ellipse.Stroke = new SolidColorBrush(Colors.Red);
                ellipse.Width = sz.Width;
                ellipse.Height = sz.Height;


                //Canvas.SetLeft(ellipse, -lc.X + App.ShakeImagePos.X);
                //Canvas.SetTop(ellipse,  -lc.Y + App.ShakeImagePos.Y);

                //circle.ellipse.SetValue(Canvas.LeftProperty, lc.X);
                //circle.ellipse.SetValue(Canvas.TopProperty, lc.Y);
                //circle.rectangle.SetValue(Canvas.LeftProperty, lc.X);
                //circle.rectangle.SetValue(Canvas.TopProperty, lc.Y);
                //shakePanel.Children.Add(circle.ellipse);
                //shakePanel.Children.Add(circle.rectangle);

                //ellipses.Add(circle);
                //Graphics g = Graphics.FromImage(pictureClip);

                //Brush tBrush = new TextureBrush(img, System.Drawing.Drawing2D.WrapMode.Clamp, new Rectangle((int)lc.X, (int)lc.Y, sz.Width, sz.Height));
                WriteableBitmap texture = new WriteableBitmap((int)ellipse.Width, (int)ellipse.Height);
                texture.Render(ellipse, new TranslateTransform());
                texture.Invalidate();
                Texture2D txt = new Texture2D(gd, texture.PixelWidth, texture.PixelHeight);
                txt.SetData(App.BGRAToRGBA(texture));
                texturesList.Add(txt);


            }
            float radius = (ConvertUnits.ToSimUnits(siz.Width) + ConvertUnits.ToSimUnits(siz.Height)) / 4;
            //radius = radius * minStep / StepFraction;
            _circle = BodyFactory.CreateCircle(World, radius, 1f);
            _circle.BodyType = BodyType.Dynamic;
            _circle.Mass = 10;
            _circle.LinearDamping = 2;
            _circle.UserData = radius;
            //_circle.Position = ConvertUnits.ToSimUnits(new Microsoft.Xna.Framework.Vector2((float)destination.X - ConvertUnits.ToDisplayUnits(radius), (float)destination.Y - ConvertUnits.ToDisplayUnits(radius)));
            _circle.Position = ConvertUnits.ToSimUnits(new Microsoft.Xna.Framework.Vector2((float)destination.X, (float)destination.Y ));
            //_circle.IgnoreCCD = 
            circle = createellipsetexture(new Size(ConvertUnits.ToDisplayUnits(radius * 2), ConvertUnits.ToDisplayUnits(radius * 2)));
            //joint = new FixedDistanceJoint(_circle, _circle.LocalCenter, _circle.Position);
            joint = new FixedDistanceJoint(_circle, _circle.LocalCenter, _circle.Position);
            joint.Frequency = 1.8f;
            joint.DampingRatio = 0.8f;
            joint.Length = 0f;
            World.AddJoint(joint);
            return texturesList.First();
        }

        public Texture2D circle;
        private Texture2D createellipsetexture(Size sz)
        {
            Ellipse ellipse = new Ellipse();

            ellipse.Fill = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Red);

            ellipse.StrokeThickness = 1;
            ellipse.Stroke = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Red);
            ellipse.Width = sz.Width;
            ellipse.Height = sz.Height;
            WriteableBitmap texture = new WriteableBitmap((int)ellipse.Width, (int)ellipse.Height);
            texture.Render(ellipse, new System.Windows.Media.TranslateTransform());
            texture.Invalidate();
            Texture2D txt = new Texture2D(Microsoft.Xna.Framework.SharedGraphicsDeviceManager.Current.GraphicsDevice, texture.PixelWidth, texture.PixelHeight);
            txt.SetData(App.BGRAToRGBA(texture));
            return txt;
        }

        FixedDistanceJoint joint;
        public  Body _circle;
        Sprite _circleTexture;
        public bool drag = false;
        Point ObjectDragPoint;
        public void objMouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            mainellipse.ReleaseMouseCapture();
            drag = false;

        }

        public void objMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            Point p = e.GetPosition(null);

            Point loc = new Point(Canvas.GetLeft(this) + (p.X - ObjectDragPoint.X), Canvas.GetTop(this) + (p.Y - ObjectDragPoint.Y));
            setpos(loc);
            ObjectDragPoint = p;

        }
        private System.Threading.Timer hideRemoveButtonTimer;
        public void objMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            ellipse1.Visibility = System.Windows.Visibility.Visible;
            if (hideRemoveButtonTimer != null)
                hideRemoveButtonTimer.Change(5000, System.Threading.Timeout.Infinite);
            else
                hideRemoveButtonTimer = new System.Threading.Timer(hideRemoveButton, null, 5000, System.Threading.Timeout.Infinite);

            mainellipse.CaptureMouse();
            ObjectDragPoint = e.GetPosition(null);
            drag = true;
            e.Handled = true;

        }
        private void hideRemoveButton(Object stateInfo)
        {
            hideRemoveButtonTimer = null;
            Dispatcher.BeginInvoke(() =>
            {
                ellipse1.Visibility = System.Windows.Visibility.Collapsed;
            });

        }
      

        public void setpos(Point l)
        {
            // this.location = l;
            this.destination = l;
            //this.forcePoint = new Point(0, 0);
            Canvas.SetLeft(this, l.X);
            Canvas.SetTop(this, l.Y);
        }


        public float Distance(Point A, Point B)
        {
            return (float)Math.Sqrt(Math.Pow((double)(A.X - B.X), 2) + Math.Pow((double)(A.Y - B.Y), 2));
        }

        //public void Move(double x, double y)
        //{
        //    //textBlock1.Text = string.Format("{0}\n{1}", x, y);
        //    Point newP = new Point(this.location.X + x, this.location.Y + y);

        //    double dist = Distance(newP, destination);
        //    if (dist > (double)(this.size.Width + this.size.Height) / 2)
        //    {
        //        dist = (double)(this.size.Width + this.size.Height) / 2;
        //        x = Math.Sign(x) * Math.Sqrt(Math.Pow(dist, 2) - Math.Pow(y, 2));
        //        y = Math.Sign(y) * Math.Sqrt(Math.Pow(dist, 2) - Math.Pow(x, 2));
        //        //this.forcePoint = new Point(x, y);
        //    }
        //    else
        //        this.forcePoint = new Point(x, y); //newP;// this.location = newP;

        //}
        public void Move(Simple3DVector v)
        {
            //textBlock1.Text = string.Format("{0}\n{1}", x, y);
            //Point newP = new Point(this.location.X + x, this.location.Y + y);

            //double dist = Distance(newP, destination);
            //if (dist > (double)(this.size.Width + this.size.Height) / 2)
            //{
            //    dist = (double)(this.size.Width + this.size.Height) / 2;
            //    x = Math.Sign(x) * Math.Sqrt(Math.Pow(dist, 2) - Math.Pow(y, 2));
            //    y = Math.Sign(y) * Math.Sqrt(Math.Pow(dist, 2) - Math.Pow(x, 2));
            //    this.forcePoint = new Point(x, y);
            //}
            //else
            this.forcePoint = v; //newP;// this.location = newP;

        }

        Simple3DVector forcePoint;

        private double prevspeedx = 0;
        private double prevspeedy = 0;
        public void Movement(double delta)
        {


            ////if (new Point((int)this.location.X, (int)this.location.Y) != destination)
            ////{
            //    Point vector = new Point(destination.X - this.location.X + this.forcePoint.X, destination.Y - this.location.Y + this.forcePoint.Y);
            //    float dist = Distance(this.location, destination);
            //if (dist == 0) dist = 1;
            //    double speedx = prevspeedx + acceleration * delta * Math.Sign(vector.X)/ Math.Sqrt(dist);
            //    double speedy = prevspeedy + acceleration * delta * Math.Sign(vector.Y)/ Math.Sqrt(dist);
            //    //long time = DateTime.Now.Ticks - prevrender;
            //    this.location = new Point((this.location.X + speedx * delta + vector.X  / (this.size.Width + this.size.Height)), (this.location.Y + speedy * delta + vector.Y  / (this.size.Width + this.size.Height)));
            //    //if (this.forcePoint.X != 0 || this.forcePoint.Y != 0)
            //    //{
            //    //    this.forcePoint = new Point(this.forcePoint.X * 0.8, this.forcePoint.Y * 0.8);
            //    //    if (Math.Abs(this.forcePoint.X) < 0.5) this.forcePoint.X = 0;
            //    //    if (Math.Abs(this.forcePoint.Y) < 0.5) this.forcePoint.Y = 0;
            //    //}

            //    prevspeedx = speedx;
            //    prevspeedy = speedy;

            //    //this.location = new PointF((this.location.X + (vector.X * delta * acceleration * 2)/100 ), (this.location.Y + (vector.Y * delta * acceleration * 2)/100 ));
            //    //if (this.Location != defloat(newloc))
            //    //{
            //    //    this.Location = defloat(newloc);
            //    //    //prevrender = DateTime.Now.Ticks;
            //    //    prevloc = newloc;
            //    //}


            ////}
            ////}
            ////else
            ////    this.Location = defloat(dest);
        }

        public void Render(SpriteBatch spriteBatch)
        {



            //LineBatch.DrawLine(spriteBatch, Color.Red, ConvertUnits.ToDisplayUnits(joint.WorldAnchorA), ConvertUnits.ToDisplayUnits(joint.WorldAnchorB));

            //Canvas.SetLeft(this, this.location.X);
            //Canvas.SetTop(this, this.location.Y);
            // setpos(elipseList.First(), this.location);
            //drawellipse(g, new RectangleF(this.location, this.size));
            try
            {
                Microsoft.Xna.Framework.Vector2 loc = ConvertUnits.ToDisplayUnits(this.joint.WorldAnchorA);
                //loc = Microsoft.Xna.Framework.Vector2.Add(loc, new Microsoft.Xna.Framework.Vector2(ConvertUnits.ToDisplayUnits((float)_circle.UserData)));
                Microsoft.Xna.Framework.Vector2 dest = ConvertUnits.ToDisplayUnits(this.joint.WorldAnchorB);
                double X = loc.X - dest.X;
                double Y = loc.Y - dest.Y ;
                //drawellipse(g, this.Bounds);
                // Texture2D txt = texturesList.Last();
                Size siz = getsize();
                foreach (Texture2D txt in texturesList)
                {



                    Microsoft.Xna.Framework.Vector2 pos = new Microsoft.Xna.Framework.Vector2((float)(loc.X - X * txt.Width * txt.Width / (siz.Width * siz.Width)), (float)(loc.Y - Y * txt.Height * txt.Height / (siz.Height * siz.Height)));
                    //pos.X += (float)siz.Width / 2 - txt.Width / 2 - siz.Width;
                    //pos.Y += (float)siz.Height / 2 - txt.Height / 2 - siz.Width;
                    pos.X += -txt.Width / 2;// +ConvertUnits.ToDisplayUnits((float)_circle.UserData);
                    pos.Y += -txt.Height / 2;// +ConvertUnits.ToDisplayUnits((float)_circle.UserData);

                    //spriteBatch.Draw(txt, ConvertUnits.ToDisplayUnits(_rectangle.Position),
                    //                    null,
                    //                     Color.White, _rectangle.Rotation, Vector2.Zero, 1, SpriteEffects.None, 0);
                    txt.Tag = pos;
                    //spriteBatch.Draw(txt, pos, Microsoft.Xna.Framework.Color.White);

                    //TranslateTransform tt = new TranslateTransform();
                    //tt.X = pos.X;
                    //tt.Y = pos.Y;
                    //circ.RenderTransform = tt;



                    //Canvas.SetLeft(circ, pos.X);
                    //Canvas.SetTop(circ, pos.Y);

                    //Canvas.SetLeft(rect, pos.X);
                    //Canvas.SetTop(rect, pos.Y);
                }
                circle.Tag = Microsoft.Xna.Framework.Vector2.Add(loc,new Microsoft.Xna.Framework.Vector2(-circle.Width/2,-circle.Height/2));
                //g.DrawString(string.Format("{0}:{1}", this.location.X, this.location.Y), SystemFonts.DefaultFont, Brushes.Red, this.location);
            }
            catch (Exception ex)
            {
                //TODO
            }

        }



        private void ellipse1_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            ellipse1.CaptureMouse();


        }

        public void delete()
        {
            App.shakeObjects.Remove(this);
            parent.Children.Remove(this);
        }

        private void ellipse1_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            ellipse1.ReleaseMouseCapture();
            this.delete();

        }

    }
}
